import axios from "axios";
import type { AxiosRequestConfig } from "axios";
import service from "./axios";
import type { ApiResponse, ApiError } from "./types";
import { useAuthStore } from "@/stores/auth/auth";
import { withAuthHeaders, buildAuthHeader } from "@/utils/http";

type RequestConfig = AxiosRequestConfig & {
  retry?: number; // 最大重试次数，默认 0
  retryDelay?: number; // 初始重试延迟 ms，默认 300
  skipAuth?: boolean; // 若 true 则不会自动注入 Authorization（如 refresh 接口）
  retryOn?: (err: any) => boolean; // 自定义重试策略（覆盖默认）
  headers?: Record<string, any>; // 允许传入自定义头
};

// 刷新队列相关（单例）
let isRefreshing = false;
let refreshSubscribers: Array<(token: string | null) => void> = [];
function subscribeToken(cb: (token: string | null) => void) {
  refreshSubscribers.push(cb);
}
function onRefreshed(token: string | null) {
  refreshSubscribers.forEach((cb) => cb(token));
  refreshSubscribers = [];
}

function sleep(ms: number) {
  return new Promise((res) => setTimeout(res, ms));
}

async function doRefreshToken(): Promise<string | null> {
  const auth = useAuthStore() as any;
  const fn = auth?.refreshAccessToken;
  if (typeof fn !== 'function') {
    // 未实现刷新逻辑则直接返回 null，交由上层处理（如跳转登录）
    return null;
  }
  try {
    const newToken = await fn.call(auth);
    return newToken;
  } catch (error) {
    try { auth.logout?.(); } catch {}
    return null;
  }
}

// 头部工具迁移到 src/utils/http.ts 统一复用

/**
 * request wrapper
 * returns ApiResponse<T>
 */
export default async function request<T = any>(
  cfg: RequestConfig,
): Promise<ApiResponse<T>> {
  const config = { retry: 0, retryDelay: 300, ...cfg } as RequestConfig;

  // 支持 AbortSignal：axios 支持 signal 字段
  const { signal } = config as any;

  let attempt = 0;
  while (true) {
    attempt++;
    try {
  // 在每次请求前合并 headers（支持自定义 + 自动注入 token）
  Object.assign(config, withAuthHeaders(config));

      const response = await service.request<ApiResponse<T>>(config);
      // 规范化返回，兼容未提供 success 字段的后端
      const payload: any = response.data ?? {};
      if (typeof payload.code === 'undefined') payload.code = response.status;
      if (typeof payload.success === 'undefined') {
        payload.success = payload.code === 0 || payload.code === 200 || response.status === 200;
      }
      if (typeof payload.message === 'undefined') payload.message = '';
      return payload as ApiResponse<T>;
    } catch (err: any) {
      // 如果请求被取消或是网络中断等，直接抛出 normalized error
      const isCancel = axios.isCancel(err) || err?.isCancel;
      if (isCancel) throw err;

      // 如果是 401 => 触发 refresh token 逻辑（排队）
      const status = err?.status ?? err?.raw?.response?.status;
      if (status === 401 && !(config as any).skipAuth) {
        // 队列逻辑：若正在刷新，则等待
        if (!isRefreshing) {
          isRefreshing = true;
          const newToken = await doRefreshToken();
          isRefreshing = false;
          onRefreshed(newToken);
        }

        // 等待刷新完成后重试当前请求
        const retryPromise = new Promise((resolve, reject) => {
          subscribeToken(async (token) => {
            if (!token) {
              // 刷新失败，直接 reject
              reject(err);
              return;
            }
            try {
              // 注入新的 token 并重试
              const authHeader = buildAuthHeader(token);
              config.headers = { ...(config.headers || {}), ...authHeader };
              const r = await service.request<ApiResponse<T>>(config);
              resolve(r.data);
            } catch (e) {
              reject(e);
            }
          });
        });
        return retryPromise as Promise<ApiResponse<T>>;
      }

      // 非 401 情况下处理重试（只对幂等请求生效）
      const method = (config.method || "get").toLowerCase();
      const idempotent = ["get", "head", "options"].includes(method);
      const shouldRetry =
        typeof config.retryOn === "function"
          ? config.retryOn(err)
          : idempotent && attempt <= (config.retry ?? 0);

      if (shouldRetry) {
        // 指数退避 (exponential backoff)
        const delay = (config.retryDelay ?? 300) * Math.pow(2, attempt - 1);
        await sleep(delay);
        continue; // 再试一次
      }

      // 非重试、非 401：抛出错误（已 normalize）
      throw err;
    }
  }
}
